package vip.xumy.core.http;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import lombok.extern.log4j.Log4j2;

/**	All rights reserved
 *	author:mengyxu
 *	date:2019年5月25日
 */

@Log4j2
@SuppressWarnings("all")
public class HttpService {
	private static final String ENCODING_UTF8 = "UTF-8";

	private static final PoolingHttpClientConnectionManager cm;

	private static final RequestConfig config;
	
	private static CookieStore cookieStore = new BasicCookieStore();

	static{
		cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(200);
		cm.setDefaultMaxPerRoute(20);

		config = RequestConfig.custom().setConnectTimeout(100000)
				.setConnectionRequestTimeout(50000).setSocketTimeout(100000)
				.setStaleConnectionCheckEnabled(true).build();
	}
	
	/**
	 * 设置请求所携带cookie
	 * @param cookies
	 */
	public static void setCookies(Map<String, String> cookies) {
		cookieStore = new BasicCookieStore();
		if(cookies != null) {
			for (String key : cookies.keySet()) {
				String value = cookies.get(key);
				BasicClientCookie clientCookie = new BasicClientCookie(key, value);
				clientCookie.setVersion(0);
				clientCookie.setSecure(false);
				clientCookie.setDomain(".");
				clientCookie.setPath("/");
				cookieStore.addCookie(clientCookie);
			}
		}
	}

	/**
	 * 带参数的get请求
	 * 
	 * @param url
	 * @param map
	 * @return
	 */
	public static HttpResult doGet(String url, Map<String, Object> param) {
		try {
			// 1.创建URIBuilder
			URIBuilder uriBuilder = new URIBuilder(url);

			// 2.设置请求参数
			if (param != null) {
				// 遍历请求参数
				for (Map.Entry<String, Object> entry : param.entrySet()) {
					// 封装请求参数
					uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
				}
			}
			
			// 3.创建请求对象httpGet
			HttpGet httpGet = new HttpGet(uriBuilder.build());
			httpGet.setConfig(config);
			// 4.使用httpClient发起请求
			CloseableHttpResponse response = HttpClients.custom().setDefaultCookieStore(cookieStore).setConnectionManager(cm).build()
					.execute(httpGet);

			// 5.解析返回结果，封装返回对象httpResult
			return getResult(response);
		} catch (Exception e) {
			log.error("http request failed",e);
			return new HttpResult(500, "http request failed");
		}
	}

	/**
	 * 不带参数的get
	 * 
	 * @param url
	 * @return
	 */
	public static HttpResult doGet(String url) {
		return doGet(url, null);
	}
	

	/**
	 * 带参数的post请求
	 * 
	 * @param url
	 * @param map
	 * @return
	 * @
	 */
	public static HttpResult doPost(String url, Map<String, Object> param) {
		try {
			// 1. 声明httppost
			HttpPost httpPost = new HttpPost(url);
			httpPost.setHeader("Accept", "application/json");
			httpPost.setHeader("Content-Type", "application/json");
			String charSet = "UTF-8";

			// 2.封装请求参数，请求数据是表单
			if (param != null) {
				// 声明封装表单数据的容器
				List<NameValuePair> parameters = new ArrayList<NameValuePair>();
				for (Map.Entry<String, Object> entry : param.entrySet()) {
					// 封装请求参数到容器中
					parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
				}

				// 创建表单的Entity对象
				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters, ENCODING_UTF8);

				// 3. 把封装好的表单实体对象设置到HttpPost对象
				httpPost.setEntity(entity);
			}
			
			// 4. 使用Httpclient发起请求
			CloseableHttpResponse response = HttpClients.custom().setDefaultCookieStore(cookieStore).setConnectionManager(cm).build()
					.execute(httpPost);

			return getResult(response);
		} catch (Exception e) {
			log.error("http request failed",e);
			return new HttpResult(500, "http request failed");
		}
	}
	
	/**
	 * json格式参数的post请求
	 * 
	 * @param url 请求地址
	 * @param params json格式参数
	 * @return
	 * @
	 */
	public static HttpResult postWithJson(String url, String params, Map<String, String> headers) {
		try {
			// 1. 声明httppost
			HttpPost httpPost = new HttpPost(url);
			httpPost.setHeader("Accept", "application/json");
			httpPost.setHeader("Content-Type", "application/json");
			String charSet = "UTF-8";
			StringEntity entity = new StringEntity(params, charSet);
			httpPost.setEntity(entity);
			
			//设置http请求头
			if(headers != null) {
				for (String key : headers.keySet()) {
					httpPost.setHeader(key, headers.get(key));
				}
			}
			
			// 4. 使用Httpclient发起请求
			CloseableHttpResponse response = HttpClients.custom().setConnectionManager(cm).build().execute(httpPost);

			// 5. 解析返回数据，封装HttpResult
			return getResult(response);
		} catch (Exception e) {
			log.error("http request failed",e);
			return new HttpResult(500, "http request failed");
		}
	}

	private static HttpResult getResult(CloseableHttpResponse response) throws IOException {
		// 状态码
		int code = response.getStatusLine().getStatusCode();

		// 响应体内容
		String body = null;
		if (response.getEntity() != null) {
			body = EntityUtils.toString(response.getEntity(), ENCODING_UTF8);
		}

		return new HttpResult(code, body);
	}

	/**
	 * 不带参数的post请求
	 * 
	 * @param url
	 * @return
	 */
	public static HttpResult doPost(String url) {
		return doPost(url, null);
	}

	public static void doPostAsync(final String url, final Map<String, Object> param){
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					doPost(url, param);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
	
}
